package com.backend.demo.util;


import java.io.Serializable;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.MessageFormat;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.annotations.common.util.StringHelper;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.Configurable;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.mapping.Table;
import org.hibernate.type.Type;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * org.hibernate.id.MultipleHiLoPerTableGenerator的扩展<BR>
 * 主要是添加startValue的配置信息和生成ID时打印一个调试信息
 * 
 * @author 陈兴吉
 * @date 2008-5-5
 */
public class AutoadjustMultipleHiLoGeneratorHibernate36  {
	private static final Map<String,IdInfo> map = new ConcurrentHashMap<String, IdInfo>();
	
	private static final Logger _log = LoggerFactory
			.getLogger(AutoadjustMultipleHiLoGeneratorHibernate36.class);

	public static final int DEFAULT_START_VALUE = 0;

	public static final String DEFAULT_PK_COLUMN = "sequence_name";
	public static final String DEFAULT_VALUE_COLUMN = "seq_next_hi_val";
	public static final String DEFAULT_TABLE = "hibernate_seq";
	
	public static final int DEFAULT_MAX_LO = 10000;
	protected int startValue;
	protected String _query = null;
	protected String _insert = null;
	protected String _update = null;
	protected String _tableName = null;

	protected int _maxLo;
	protected long _hi = 0;
	protected int _lo;
	protected Class<?> _returnClass;

	private String selectMaxSQL = null;

	public Serializable doWorkInCurrentTransaction(Connection conn, String sql)
			throws SQLException {
		// 这个结果是高位,保存在数据库中的值.
		int result = 0;
		int updateRows = 0;
		int nextInTable; // 表中ID的最大值
		boolean isNeedInitValue = false; // 是否每一次都去重新计算高位
		int errorCount = 0;
		int maxErrorCount = 6;
		do {
			//SQL.debug(_query);
			PreparedStatement qps = conn.prepareStatement(_query);
			PreparedStatement ips = null;
			try {
				ResultSet rs = qps.executeQuery();
				// 判断是否需要初始化或重新设置值
				boolean notNext = isNeedInit(rs);
				// 没有初始化,则代表ID表中,没有该表主键的记录
				if (isNeedInitValue && !notNext) {
					nextInTable = this.getNext(conn);
					_log.debug("表中记录最大值为的下一个值 : " + nextInTable);
					int curVal = nextInTable - 1;// 当前值
					if (curVal == 0) {
						return 0;
					}

					int tmp = curVal / (_maxLo + 1);
					result = tmp + 1;

					ips = conn.prepareStatement(_insert);
					ips.setInt(1, result);
					ips.execute();
				} else if (!notNext){
					ips = conn.prepareStatement(_insert);
					ips.setInt(1, result);
					ips.execute();
					result = 0;
				} else {
					result = rs.getInt(1);
				}
				rs.close();
			} catch (SQLException sqle) {
				if(++errorCount > maxErrorCount){
					throw sqle;
				} else {
					_log.error("不能从数据库读取高位的记录，准备再执行一次，当前已错误次数："+errorCount+"/"+maxErrorCount, sqle);
					try {
						Thread.sleep(100L);
					} catch (InterruptedException e) {
					}
					continue;
				}
			} finally {
				DBUtil.closePreparedStatement(ips);
				DBUtil.closePreparedStatement(qps);
			}

			// sql = update;
			PreparedStatement ups = conn.prepareStatement(_update);
			try {
				ups.setInt(1, result + 1);// 新值
				ups.setInt(2, result);// 旧值
				updateRows = ups.executeUpdate();
			} catch (SQLException sqle) {
				_log.error("could not update hi value in: " + _tableName, sqle);
				throw sqle;
			} finally {
				ups.close();
			}
		} while (updateRows == 0);
		return new Integer(result);
	}

	/**
	 *  判断是否需要初始化或重新设置值
	 *  
	 * @param rs
	 * @return
	 * @throws SQLException
	 */
	private boolean isNeedInit(ResultSet rs) throws SQLException {
		return rs.next();
	}

	

	

	

	/**
	 * 从 IncrementGenerator copy过来,重表中,得到ID得最大的值
	 * 
	 * @param session
	 * @param params
	 * @param type
	 * @return
	 */
	private int getNext(Connection conn) {
		long next;
		PreparedStatement st = null;
		ResultSet rs = null;
		try {
			_log.debug("准备得到下该表就最大值，SQL: " + selectMaxSQL);
			st = conn.prepareStatement(selectMaxSQL);
			rs = st.executeQuery();
			try {
				if (isNeedInit(rs)) {
					next = rs.getLong(1) + 1;
					if (rs.wasNull()){
						next = 1;
					}
				} else {
					next = 1;
				}
				selectMaxSQL = null;
			} finally {
				if (rs != null) {
					rs.close();
				}
				if (st != null) {
					st.close();
				}
			}
		} catch (SQLException sqle) {
			throw new RuntimeException(sqle);
		}
		int ret = new Long(next).intValue();
		_log.debug("完成得到下该表就最大值。下一个值为 ：" + ret);
		return ret;
	}
	
	/**
	 *  主键的一些信息
	 */
	public static class IdInfo{
		private String selectMaxSQL;
		private String tableName;
		private int maxLo = DEFAULT_MAX_LO;
		
		public int getMaxLo() {
			return maxLo;
		}
		public void setMaxLo(int maxLo) {
			this.maxLo = maxLo;
		}
		public String getSelectMaxSQL() {
			return selectMaxSQL;
		}
		public void setSelectMaxSQL(String selectMaxSQL) {
			this.selectMaxSQL = selectMaxSQL;
		}
		public String getTableName() {
			return tableName;
		}
		public void setTableName(String tableName) {
			this.tableName = tableName;
		}
		public String toString(){
			return tableName + ":" + selectMaxSQL;
		}
	}
	
	public static IdInfo getIdInfo(String tableName){
		return map.get(tableName);
	}
	
}